using System;
using System.Collections.Generic;
using System.Text;

using SBPweb.Modules.Modularity;

namespace SBPweb.Contracts.Implementation
{
	/// <summary>
	/// Class of LayoutService
	/// </summary>
	public class LayoutService : ILayoutService
	{
		#region Private members

		private IModuleHost pHost;
		private bool pIsInitialized;
		private LayoutGroup pLayoutGroup;

		#endregion

		#region Constructor logic

		/// <summary>
		/// Constructor of LayoutService
		/// </summary>
		/// <param name="host"></param>
		public LayoutService(IModuleHost host)
		{
			pHost = host;
			pIsInitialized = false;

			host.ModuleLoader.ModuleGroupLoaded += new EventHandler(ModuleLoader_ModuleGroupLoaded);
			host.ModuleLoader.ModuleGroupUnloading += new EventHandler(ModuleLoader_ModuleGroupUnloading);
		}

		#endregion

		#region Public properties

		#region ILayoutService Members

		/// <summary>
		/// Layout group
		/// </summary>
		public LayoutGroup LayoutGroup
		{
			get 
			{
				return pLayoutGroup;
			}
		}

		/// <summary>
		/// Layout provider
		/// </summary>
		public ILayoutProvider LayoutProvider
		{
			get 
			{
				return pHost.LayoutProvider;
			}
		}

		/// <summary>
		/// Returns the layout's group name
		/// </summary>
		public string LayoutGroupName
		{
			get
			{
				return pLayoutGroup != null ? pLayoutGroup.LayoutGroupName : string.Empty;
			}
		}

		/// <summary>
		/// Returns the selected layout
		/// </summary>
		public string SelectedLayout
		{
			get
			{
				return pLayoutGroup != null ? pLayoutGroup.SelectedLayout : string.Empty;
			}
		}

		/// <summary>
		/// Is initialized?
		/// </summary>
		public bool IsInitialzed
		{
			get
			{
				return pIsInitialized;
			}
		}
		#endregion

		#region IService Members

		/// <summary>
		/// Name
		/// </summary>
		public string Name
		{
			get 
			{
				return "LayoutService";
			}
		}

		/// <summary>
		/// Module
		/// </summary>
		public IModule Module
		{
			get 
			{
				return null;
			}
		}

		#endregion

		#region IPersistable Members

		/// <summary>
		/// Persistency key
		/// </summary>
		public string PersistencyKey
		{
			get 
			{
				return this.GetType().Name;
			}
		}

		/// <summary>
		/// Return parent as persistabls
		/// </summary>
		public IPersistable ParentPersistable
		{
			get 
			{
				return pHost;
			}
		}

		#endregion

		/// <summary>
		/// Persistency service
		/// </summary>
		public IStatePersistenceService PersistenceService
		{
			get
			{
				return pHost.ModuleLoader.Services.Get<IStatePersistenceService>();
			}
		}

		#endregion

		#region Public methods

		#region Initialization

		/// <summary>
		/// Initialize
		/// </summary>
		/// <param name="layoutGroupName"></param>
		public void Initialize(string layoutGroupName)
		{
			if (pIsInitialized)
			{
				Terminate();
			}
			pLayoutGroup = new LayoutGroup(this, PersistenceService, layoutGroupName);
			pLayoutGroup.LoadPersistency();
			pIsInitialized = true;
		}

		/// <summary>
		/// Terminate
		/// </summary>
		public void Terminate()
		{
			if (pIsInitialized)
			{
				pLayoutGroup.SavePersistency();
				pLayoutGroup = null;
				pIsInitialized = false;
			}
		}

		#endregion

		#region Layout handling

		/// <summary>
		/// Deletes layout
		/// </summary>
		/// <param name="name">name</param>
		/// <returns>success</returns>
		public bool DeleteLayout(string name)
		{
			if (pLayoutGroup.Layouts.ContainsKey(name))
			{
				pLayoutGroup.Layouts.Remove(name);
				if (pLayoutGroup.SelectedLayout == name)
				{
					pLayoutGroup.SelectedLayout = string.Empty;
				}
				if (LayoutDeleted != null)
				{
					LayoutDeleted(this, new EventArgs());
				}
				return true;
			}
			return false;
		}

		/// <summary>
		/// Renames a layout
		/// </summary>
		/// <param name="oldName">old name</param>
		/// <param name="newName">new name</param>
		/// <returns>success</returns>
		public bool RenameLayout(string oldName, string newName)
		{
			if (pLayoutGroup.Layouts.ContainsKey(oldName))
			{
				Layout layout = pLayoutGroup.Layouts[oldName];
				layout.Name = newName;
				pLayoutGroup.Layouts.Remove(oldName);
				if (pLayoutGroup.Layouts.ContainsKey(newName))
				{
					pLayoutGroup.Layouts[newName] = layout;
				}
				else
				{
					pLayoutGroup.Layouts.Add(newName, layout);
				}
				if (pLayoutGroup.SelectedLayout == oldName)
				{
					pLayoutGroup.SelectedLayout = newName;
				}

				if (LayoutRenamed != null)
				{
					LayoutRenamed(this, new EventArgs());
				}
				return true;
			}
			return false;
		}

		/// <summary>
		/// Saves a layout
		/// </summary>
		/// <param name="name">name</param>
		/// <returns>success</returns>
		public bool SaveLayout(string name)
		{
			string currentLayout = pHost.LayoutProvider.GetLayout();
			Layout layout = new Layout(pLayoutGroup, PersistenceService, name, currentLayout);
			RefreshModuleDictionary(layout.Modules);
			if (pLayoutGroup.Layouts.ContainsKey(name))
			{
				pLayoutGroup.Layouts[name] = layout;
			}
			else
			{
				pLayoutGroup.Layouts.Add(name, layout);
			}
			pLayoutGroup.SelectedLayout = name;

			if (LayoutSaved != null)
			{
				LayoutSaved(this, new EventArgs());
			}
			return true;
		}

		/// <summary>
		/// Loads a layout
		/// </summary>
		/// <param name="name">name</param>
		/// <returns>success</returns>
		public bool LoadLayout(string name)
		{
			if (pLayoutGroup.Layouts.ContainsKey(name))
			{
				if (LayoutLoading != null)
				{
					LayoutLoading(this, new EventArgs());
				}

				RefreshLayoutModules(name);

				pHost.LayoutProvider.SetLayout(pLayoutGroup.Layouts[name].LayoutString);
				pLayoutGroup.SelectedLayout = name;

				if (LayoutLoaded != null)
				{
					LayoutLoaded(this, new EventArgs());
				}
				return true;
			}
			return false;
		}
		
		#endregion

		#endregion

		#region Event handlers

		void ModuleLoader_ModuleGroupUnloading(object sender, EventArgs e)
		{
			Terminate();
			if (Terminated != null)
			{
				Terminated(this, new EventArgs());
			}
		}

		void ModuleLoader_ModuleGroupLoaded(object sender, EventArgs e)
		{
			Initialize(pHost.ModuleLoader.CurrentModuleGroupName);
			if (Initialized != null)
			{
				Initialized(this, new EventArgs());
			}
		}

		#endregion

		#region Public events

		/// <summary>
		/// Event for initialization
		/// </summary>
		public event EventHandler Initialized;
		/// <summary>
		/// Event for termination
		/// </summary>
		public event EventHandler Terminated;
		/// <summary>
		/// Event before layout load
		/// </summary>
		public event EventHandler LayoutLoading;
		/// <summary>
		/// Event for layout load
		/// </summary>
		public event EventHandler LayoutLoaded;
		/// <summary>
		/// Event for layout save
		/// </summary>
		public event EventHandler LayoutSaved;
		/// <summary>
		/// Event for layout renaming
		/// </summary>
		public event EventHandler LayoutRenamed;
		/// <summary>
		/// Event for layout deletion
		/// </summary>
		public event EventHandler LayoutDeleted;

		#endregion

		#region Private helper methods

		private void RefreshLayoutModules(string name)
		{
			if (pLayoutGroup.Layouts.ContainsKey(name))
			{
				Dictionary<string, ModuleInfo> currentModuleInfos = pHost.ModuleLoader.CurrentModulesDictionary; 
				foreach (string moduleTypeName in pLayoutGroup.Layouts[name].Modules.Keys)
				{
					bool loaded = false;
					if (bool.TryParse(pLayoutGroup.Layouts[name].Modules[moduleTypeName], out loaded))
					{
						if (currentModuleInfos.ContainsKey(moduleTypeName))
						{
							ModuleInfo mi = currentModuleInfos[moduleTypeName];
							if (loaded && !mi.ModuleDescriptor.Loaded)
							{
								pHost.ModuleLoader.LoadModule(mi);
							}
							if (!loaded && mi.ModuleDescriptor.Loaded && mi.AllowUnload)
							{
								pHost.ModuleLoader.UnloadModule(mi);
							}
						}
					}
				}
			}
		}

		private void RefreshModuleDictionary(PersistableDictionary modules)
		{
			if (pHost.ModuleLoader.CurrentModuleGroupName == pLayoutGroup.LayoutGroupName)
			{
				modules.Clear();
				foreach (ModuleInfo mi in pHost.ModuleLoader.CurrentModuleList)
				{
					if (!mi.IsCoreModule)
					{
						modules.Add(mi.ModuleDescriptor.ModuleTypeName, mi.ModuleDescriptor.Loaded.ToString());
					}
				}
			}
		}

		#endregion
	}
}
